home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / ISSUE06 / INTERNAL / DOSINFO.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1996-01-11  |  5.9 KB  |  202 lines

  1. unit DOSInfo;
  2.  
  3. interface
  4.  
  5. uses WinTypes, WinProcs, WinDOS, Strings;
  6.  
  7. function GetFloppyDriveCount: Integer;
  8. function GetFloppyDriveType (index: Integer): Integer;
  9. function GetDriveLabel (drive: Integer): String;
  10. function SetDriveLabel (drive: Integer; VolLabel: String): Integer;
  11.  
  12. implementation
  13.  
  14. type XFCB = record              { prehistoric extended FCB - yuck }
  15.     extSig: Byte;              { must be $FF for extended flag }
  16.     extRes: array [0..4] of Byte;     { reserved stuff }
  17.     extAttr: Byte;              { file attribute }
  18.     extDrive: Byte;              { drive number }
  19.     extFName: array [0..10] of Char;  { filename }
  20.     extJunk: array [0..24] of Byte;   { rest of the junk is irrelevant }
  21. end;
  22.  
  23. { Read a single byte from CMOS memory }
  24.  
  25. function ReadCMOSByte (idx: Byte): Word; assembler;
  26. asm
  27.     mov al,idx                  { get the wanted index           }
  28.     out 70h,al                  { write address into address reg }
  29.     in  al,71h                  { read the drive type into AL    }
  30.     mov ah,0                    { clear the high byte            }
  31. end;
  32.  
  33. { Count the number of physical (not logical) floppy drives) }
  34.  
  35. function GetFloppyDriveCount: Integer;
  36. var
  37.     regs: TRegisters;
  38. begin
  39.     { Get equipment bits }
  40.     FillChar (regs, sizeof (regs), 0);
  41.     Intr ($11, regs);
  42.     if (regs.AX and 1) = 0 then GetFloppyDriveCount := 0 else
  43.     GetFloppyDriveCount := ((regs.AX and $C0) shr 6) + 1;
  44. end;
  45.  
  46. { Return the type (max KB capacity) of a given floppy drive }
  47.  
  48. function GetFloppyDriveType (index: Integer): Integer;
  49. var
  50.     flopFlags: Word;
  51.  
  52.     function FlagsToKBytes (flags: Word): Integer;
  53.     begin
  54.         case flags of
  55.             0:     FlagsToKBytes := 0;
  56.             1:     FlagsToKBytes := 360;
  57.             2:     FlagsToKBytes := 1200;
  58.             3:     FlagsToKBytes := 720;
  59.             4:     FlagsToKBytes := 1440;
  60.             5:     FlagsToKBytes := 2880;
  61.             else   FlagsToKBytes := -1;
  62.         end
  63.     end;
  64.  
  65. begin
  66.     flopFlags := ReadCMOSByte ($10);
  67.     case index of
  68.         0: GetFloppyDriveType := FlagsToKBytes (flopFlags shr 4);
  69.         1: GetFloppyDriveType := FlagsToKBytes (flopFlags and 15);
  70.         else GetFloppyDriveType := 0;
  71.     end;
  72. end;
  73.  
  74. { Return the drive label of a specified drive }
  75.  
  76. function GetDriveLabel (drive: Integer): String;
  77. var
  78.     i: Integer;
  79.     s: String;
  80.     rec: WinDOS.TSearchRec;
  81.     path: array [0..10] of Char;
  82. begin
  83.     s := '';
  84.     lstrcpy (path, 'X:\*.*');
  85.     path [0] := Chr (drive + $40);               { 1=A, 2=B, etc... }
  86.     WinDOS.FindFirst (path, 8, rec);
  87.     if WinDOS.DOSError = 0 then
  88.     begin
  89.         for i := 0 to 12 do
  90.             if rec.Name [i] = #0 then break
  91.             else if rec.Name [i] <> '.' then s := s + rec.Name [i];
  92.     end;
  93.  
  94.     GetDriveLabel := s;
  95. end;
  96.  
  97. { Initialise 'fcb' for volume label twiddling - bleurgh ! }
  98.  
  99. procedure InitLabelFCB (drive: Byte; var fcb: XFCB);
  100. begin
  101.     FillChar (fcb, sizeof (fcb), 0);
  102.     with fcb do
  103.     begin
  104.         extSig := $ff;        { mark FCB as extended }
  105.      extAttr := 8;        { specify VOLUME attribute }
  106.     extDrive := drive;    { set up drive number (1=A, 2=B..) }
  107.     FillChar (extFName, sizeof (extFName), '?');
  108.     end;
  109. end;
  110.  
  111. { Trash any existing volume label }
  112.  
  113. function NukeVolumeLabel (drive: Byte): Integer;
  114. var
  115.     fcb: XFCB;
  116.     regs: TRegisters;
  117. begin
  118.     FillChar (regs, sizeof (regs), 0);
  119.     InitLabelFCB (drive, fcb);
  120.     regs.ah := $13;
  121.     regs.dx := Ofs (fcb);
  122.     regs.ds := Seg (fcb);
  123.     MSDos (regs);
  124.     NukeVolumeLabel := regs.al;
  125. end;
  126.  
  127. { This routine massages a user-supplied volume label.  It is rejected if
  128.   any invalid characters are supplied, alpha's are uppercased, and it's
  129.   converted into 8.3 format preceeded by 'X:\'. }
  130.  
  131. function MassageVolumeLabel (VolLabel: String): String;
  132. var
  133.    i: Integer;
  134.    str: String;
  135. begin
  136.    str := '';
  137.    MassageVolumeLabel := '';
  138.    { Validate the user input }
  139.    if Length (VolLabel) > 11 then VolLabel [0] := Chr (11);
  140.    for i := 1 to Length (VolLabel) do
  141.    begin
  142.        if StrScan ('*?/\|.,;:+=[]()&^<>"', VolLabel [i]) <> Nil then Exit;
  143.        if Length (str) = 8 then str := str + '.';
  144.        str := str + UpCase (VolLabel [i]);
  145.    end;
  146.  
  147.    MassageVolumeLabel := 'X:\' + str;
  148. end;
  149.  
  150. { create a volume label - assumes there's not one already there }
  151.  
  152. function CreateVolLabel (drive: Byte; volName: String): Integer;
  153. var
  154.     i: Integer;
  155.     regs: TRegisters;
  156.     path: array [0..20] of Char;
  157.  
  158. begin
  159.     CreateVolLabel := -1;
  160.     StrPCopy (path, MassageVolumeLabel (volName));
  161.     if path [0] = #0 then Exit;         { label was invalid }
  162.     path [0] := Chr (drive + $40);      { 1=A, 2=B, etc... }
  163.  
  164.     FillChar (regs, sizeof (regs), 0);  { safe p-mode programming... }
  165.     regs.ah := $3C;                     { specify create file        }
  166.     regs.cx := 8;                       { set volume label attribute }
  167.     regs.dx := Ofs (path);              { set up pointer to name     }
  168.     regs.ds := Seg (path);              { DS:DS is the pointer pair  }
  169.     MSDos (regs);                       { do the business...         }
  170.  
  171.     if not (Odd (regs.Flags)) then      { if no carry, then ok }
  172.     begin
  173.         _lclose (regs.ax);
  174.         CreateVolLabel := 0;
  175.     end;
  176. end;
  177.  
  178. { Higher-level volume settings code.  Takes care of replacing,
  179.   nuking, etc. }
  180.  
  181. function SetDriveLabel (drive: Integer; VolLabel: String): Integer;
  182. var
  183.     err: Integer;
  184.     OldLabel: String;
  185. begin
  186.     err := 0;
  187.     OldLabel := GetDriveLabel (drive);
  188.  
  189.     { If old and new labels are the same, nothing to do }
  190.     if OldLabel <> VolLabel then
  191.     begin
  192.         { If got an old label, then delete it }
  193.         if OldLabel <> '' then err := NukeVolumeLabel (drive);
  194.         { If we've got a new label, then set it up }
  195.         if (err = 0) and (VolLabel <> '') then err := CreateVolLabel (drive, volLabel);
  196.     end;
  197.  
  198.     SetDriveLabel := err;
  199. end;
  200.  
  201. end.
  202.